#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
#include <unistd.h>

using namespace std;

std::mutex                  g_mutex        ;
int                         g_count   =   0;

void Add()
{
    int count = 0;
    std::cout << "count address: " << &count << std::endl;
    thread::id this_thread_id = this_thread::get_id();
    std::cout << "this thread id: " << this_thread_id << std::endl;

    while(true) {
        g_mutex.lock();
        int i = ++g_count;
        std::cout << "g_count: " << i << std::endl;
        g_mutex.unlock();
        sleep(1);
        count++;
        if(count > 1000000) {
            break;
        }
    }
}

void Subtract()
{
    int count = 0;
    std::cout << "count address: " << &count << std::endl;

    thread::id this_thread_id = this_thread::get_id();
    std::cout << "this thread id: " << this_thread_id << std::endl;

    while(true) {
        g_mutex.lock();
        int i = --g_count;
        std::cout << "g_count: " << i << std::endl;
        g_mutex.unlock();
        sleep(1);
        count++;
        if(count > 1000000) {
            break;
        }
    }
}

int main(int argc, char *argv[])
{

    thread::id this_thread_id = this_thread::get_id();
    std::cout << "main thread: this thread id: " << this_thread_id << std::endl;
    const std::size_t SIZE = 4;
    std::vector<std::thread>            threadPool;
    threadPool.reserve(SIZE);

    for(std::size_t i = 0; i < SIZE; ++i) {
        if(i < SIZE/2) {
            threadPool.emplace_back(&Add);
        } else {
            threadPool.emplace_back(&Subtract);
        }
    }

    // wait for all threads end
    for(std::thread &t : threadPool) {
        t.join();
    }

    std::cout << "global count: " << g_count << std::endl;
    return 0;
}


//lock_guard auto lock unlock like shared_point
//#include <iostream>
//#include <mutex>
//#include <thread>
//#include <vector>

//std::mutex          g_mutex;
//int                 g_count;

//void Counter()
//{
//    std::lock_guard<std::mutex> lock(g_mutex);

//    int i = ++g_count;
//    std::cout << "count: " << i << std::endl;
//}

//int main()
//{
//    const std::size_t SIZE = 4;

//    std::vector<std::thread> threadPool;
//    threadPool.reserve(SIZE);

//    for(std::size_t i = 0; i < SIZE; ++i) {
//        threadPool.emplace_back(&Counter);
//    }

//    for(std::thread &t : threadPool) {
//        t.join();
//    }
//    return 0;
//}


// unique_lock
//#include <iostream>
//#include <mutex>
//#include <thread>
//#include <vector>
//#include <unistd.h>

//using namespace std;

//std::mutex g_mutex;
//int g_count = 0;

//void Counter() {
//    while (1) {
//        std::unique_lock<std::mutex> lock(g_mutex);
//        ++g_count;
//        --g_count;
//        int i = g_count;
//        std::cout << "count: " << i << std::endl;
//        usleep(10000);
//        cout << "thread: " << std::this_thread::get_id() << endl;
//    }
//}

//int main() {
//  const std::size_t SIZE = 4;

//  std::vector<std::thread> v;
//  v.reserve(SIZE);

//  for (std::size_t i = 0; i < SIZE; ++i) {
//    v.emplace_back(&Counter);
//  }

//  for (std::thread& t : v) {
//    t.join();
//  }

//  return 0;
//}

//#include <iostream>
//#include <mutex>
//#include <thread>
//#include <vector>

//std::mutex g_mutex;
//std::mutex g_io_mutex;
//int g_count = 0;

//void Counter() {
//  int i;
//  {
//    std::unique_lock<std::mutex> lock(g_mutex);
//    i = ++g_count;
//  }

//  {
//    std::unique_lock<std::mutex> lock(g_io_mutex);
//    std::cout << "count: " << i << std::endl;
//  }
//}

//int main() {
//  const std::size_t SIZE = 4;

//  std::vector<std::thread> v;
//  v.reserve(SIZE);

//  for (std::size_t i = 0; i < SIZE; ++i) {
//    v.emplace_back(&Counter);
//  }

//  for (std::thread& t : v) {
//    t.join();
//  }

//  return 0;
//}
